<script lang="ts" setup>
import type { CatalogListData } from './index';

import { computed, onBeforeMount, reactive, ref } from 'vue';

import { Page } from '@vben/common-ui';
import { useAppConfig } from '@vben/hooks';
import {
  ElCollection,
  ElDelete,
  ElDocumentAdd,
  ElDownload,
  ElPriceTag,
  ElSearch,
  ElUploadFilled,
  ElView,
  FaAudio,
  FluentTable,
  GravityPicture,
  IpText,
  IpVideo,
  MdiRaster,
  TablerVector,
} from '@vben/icons';

import { StorageManager } from '@vben-core/shared/cache';

import {
  ElAvatar,
  ElButton,
  ElCard,
  ElDivider,
  ElEmpty,
  ElIcon,
  ElInput,
  ElMessage,
  ElPagination,
  ElSkeleton,
  ElSkeletonItem,
} from 'element-plus';
import { Base64 } from 'js-base64';

import {
  fileApi,
  fileTagApi,
  publicResourcesApi,
  segmentApi,
  userApi,
} from '#/api';
import { PREVIEW_IP } from '#/constant';
import { $t } from '#/locales';
import { fileTag2FileSegment, getKnowledgeInfo } from '#/utils';

import {
  folderIcon,
  geojsonIcon,
  otherIcon,
  shpIcon,
  tableIcon,
  tiffIcon,
  tupianIcon,
  zipIcon,
} from './assets';
import {
  AddTagDialog,
  FileViewer,
  PreviewDialog,
  PublishDialog,
  Uploader,
} from './components';

const storageManager = new StorageManager({
  prefix: '',
  storageType: 'sessionStorage',
});

const { adminEmail } = useAppConfig(import.meta.env, import.meta.env.PROD);

const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(100);
const keyword = ref('');
const isFileViewerShow = ref(false);
const dialogImport = ref(false);
const userId = storageManager.getItem('userId');
const isPreviewDialogShow = ref(false);
const isAddTagShow = ref(false);
const isLoading = ref(true);

const previewSrc = ref('');
const tagFileId = ref('');
const tagFileName = ref('');
const uploadFileDialog = ref(false);
const publishDialog = ref(false);
const rootCatalog = storageManager.getItem('rootCatalog');
const isAdmini = ref(false);
const filterArray = [{ label: 'All (*.all)', value: 'All' }];
const imageSrc = (type: string) => {
  const iconMap: Record<string, string> = {
    csv: tableIcon,
    xls: tableIcon,
    xlsx: tableIcon,
    folder: folderIcon,
    geojson: geojsonIcon,
    json: geojsonIcon,
    gif: tupianIcon,
    jpg: tupianIcon,
    png: tupianIcon,
    shp: shpIcon,
    tif: tiffIcon,
    tiff: tiffIcon,
    zip: zipIcon,
  };

  return iconMap[type] || otherIcon;
};

const adminInfo = ref(
  {} as {
    avatar: string;
    email: string;
    institution: string;
    userName: string;
  },
);
const catalogList = reactive({
  data: [] as CatalogListData[],
});
// 选中的分类和文件类型
const selectedCategory = ref('全部');
const selectedFileTypes = ref(['ALL']);

const categories = [
  { name: '全部' },
  { name: '表格' },
  { name: '矢量' },
  { name: '图片' },
  { name: '栅格' },
  { name: '文本' },
  { name: '音频' },
  { name: '视频' },
];

const resources = {
  全部: ['ALL'],
  表格: ['CSV', 'XLSX', 'ODS'],
  矢量: ['SHP', 'GeoJSON', 'KML'],
  图片: ['JPG', 'PNG', 'SVG'],
  栅格: ['TIF', 'TIFF', 'PNG'],
  文本: ['TXT', 'PDF', 'DOCX'],
  音频: ['MP3', 'WAV', 'FLAC'],
  视频: ['MP4', 'AVI', 'MOV'],
};

const icons = {
  全部: ElCollection,
  表格: FluentTable,
  矢量: TablerVector,
  图片: GravityPicture,
  栅格: MdiRaster,
  文本: IpText,
  音频: FaAudio,
  视频: IpVideo,
};

// 选中分类时
const selectCategory = (category: string) => {
  if (selectedCategory.value === category) {
    selectedCategory.value = null;
    selectedFileTypes.value = [];
  } else {
    selectedCategory.value = category;
    selectedFileTypes.value = resources[category];
  }
};

// 选中子类型（pills）
const selectFileType = (format: string, category: string) => {
  if (format === 'ALL') {
    selectedFileTypes.value = ['ALL'];
    selectedCategory.value = category;
  } else {
    // 当 category 发生变化时，重置选中状态
    if (selectedCategory.value !== category) {
      selectedFileTypes.value = [];
    }

    // 确保 ALL 不再被选中
    if (selectedFileTypes.value.includes('ALL')) {
      selectedFileTypes.value = [];
    }

    // 切换选中状态
    if (selectedFileTypes.value.includes(format)) {
      selectedFileTypes.value = selectedFileTypes.value.filter(
        (f) => f !== format,
      );
    } else {
      selectedFileTypes.value.push(format);
    }

    // 更新类别
    selectedCategory.value =
      selectedFileTypes.value.length === 0 ? null : category;
  }
};

const filteredFiles = computed(() => {
  return catalogList.data.filter((file) => {
    const fileTypeLower = file.type.toLowerCase();
    const fileNameLower = file.name.toLowerCase();
    const keywordLower = keyword.value?.toLowerCase() || '';

    // **类别过滤**
    const matchesCategory =
      selectedCategory.value === '全部' || selectedCategory.value === null
        ? true
        : resources[selectedCategory.value]
            ?.map((type: string) => type.toLowerCase())
            .includes(fileTypeLower);

    const matchesFileType =
      selectedFileTypes.value.length === 0 ||
      selectedFileTypes.value.includes('ALL') ||
      selectedFileTypes.value
        .map((type) => type.toLowerCase())
        .includes(fileTypeLower);

    const matchesKeyword = keywordLower
      ? fileNameLower.includes(keywordLower)
      : true;

    return matchesCategory && matchesFileType && matchesKeyword;
  });
});

const uploadFile = () => {
  uploadFileDialog.value = true;
};
const isAdmin = () => {
  if (storageManager.getItem('email') === adminEmail) isAdmini.value = true;
};

const handleCloseFileViewer = () => {
  isFileViewerShow.value = false;
};
const handleCloseDialog = () => {
  isAddTagShow.value = false;
};

const addTags = (fileid: string, filename: string) => {
  isAddTagShow.value = true;
  tagFileId.value = fileid;
  tagFileName.value = filename;
};

const refreshPublicResources = async (delay: number = 300) => {
  try {
    const response = await publicResourcesApi.getFileList(
      pageSize.value,
      currentPage.value,
      keyword.value,
    );
    if (response) {
      setTimeout(() => {
        catalogList.data = response.body;
        total.value = response.count;
      }, delay);
    }
    setTimeout(() => {
      isLoading.value = false;
    }, 500);
  } catch (error) {
    console.error('Error when fetching catalog list:', error);
  }
};
const realSelectedFileData = ref<any>(null);

const showPublishDialog = (id: string, name: string, type: string) => {
  publishDialog.value = true;
  realSelectedFileData.value = computed(() => {
    return {
      id,
      label: name,
      type,
      catalogId: storageManager.getItem('currentCatalogId'),
    } as any;
  });
};
const handleSizeChange = (_val: number) => {};
const handleCurrentChange = (val: number) => {
  currentPage.value = val;
  refreshPublicResources();
};

// 删除文件 file
const performDeleteFile = async (fileId: string) => {
  await publicResourcesApi.deleteFile(fileId);
  refreshPublicResources();
};

const deletePublic = async (fileId: string) => {
  await performDeleteFile(fileId);
  ElMessage.success($t('page.resources.deleteFileSuccessMessage'));
};
const currentSelectedFile = ref<CatalogListData>({} as CatalogListData);
const getResourceInfo = async (file: CatalogListData) => {
  currentSelectedFile.value = await fileApi.getFileInfo(file.id);
};
const handleClosePreviewDialog = () => {
  isPreviewDialogShow.value = false;
};
const importFile = ref('');

const importResouce = (fileId: string) => {
  isFileViewerShow.value = true;
  importFile.value = fileId;
};

const confirmFileImport = async (catalog: any) => {
  try {
    // 1. 获取当前文件的标签信息
    const currentTagsResponse = await fileTagApi.getFileTag(importFile.value);
    if (!currentTagsResponse) {
      ElMessage.error('获取当前文件标签失败，请重试！');
      throw new Error('获取标签失败');
    }

    // 2. 调用导入接口，将文件导入个人数据空间
    const importResponse = await publicResourcesApi.importFile2Resources(
      userId as string,
      importFile.value,
      catalog.id,
    );

    ElMessage.success('导入资源成功！');

    delete currentTagsResponse.fileId;
    delete currentTagsResponse.fileName;

    // 3. 更新新文件的标签
    const newFileId = importResponse;
    await fileTagApi.updateFileTag(newFileId, currentTagsResponse);
    // 4. 更新知识库
    const { datasetId, documentId } = await getKnowledgeInfo();
    if (!(datasetId && documentId)) {
      return;
    }
    const payload = {
      fileId: newFileId,
      fileName: currentSelectedFile.value.name,
      ...currentTagsResponse,
    };
    const text = fileTag2FileSegment([payload])
      .map((item) => JSON.stringify(item, null, 2))
      .join('#');
    await segmentApi.addSegment(datasetId, documentId, [{ content: text }]);

    // 5. 刷新公共资源列表
    refreshPublicResources(0);
  } catch (error) {
    console.error('请求出错:', error);
    return false;
  } finally {
    isFileViewerShow.value = false;
  }
};

// 下载
const downloadFile = (fileId: string, fileName: string) => {
  fileApi
    .downloadFile(fileId)
    .then((response) => {
      // @ts-ignore
      const blob = new Blob([response]);
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = fileName;
      a.click();
      URL.revokeObjectURL(url);
    })
    .catch((error) => {
      console.error('文件下载失败:', error);
    });
};

// 预览
const previewData = (fileId: string) => {
  fileApi
    .getFilePreviewUrl(fileId)
    .then((response) => {
      if (response) {
        return response;
      } else {
        throw new Error(`请求错误，${response}`);
      }
    })
    .then((data) => {
      const previewURL = data;
      const previewURLString = previewURL.toString();
      const base64String = Base64.encode(previewURLString);
      previewSrc.value = `${PREVIEW_IP}/onlinePreview?url=${encodeURIComponent(
        base64String,
      )}`;
      isPreviewDialogShow.value = true;
    })
    .catch((error) => {
      console.error(error);
    });
};

const getAdminInfo = async () => {
  const res = await userApi.getUserInfoByEmail(adminEmail);
  adminInfo.value = res;
};
onBeforeMount(async () => {
  isLoading.value = true;
  isAdmin();
  await refreshPublicResources();
  await getAdminInfo();
  // isLoading.value = false;
});
</script>

<template>
  <Page
    oncontextmenu="return false"
    onselectstart="return false"
    title=""
    auto-content-height
    class="flex h-full flex-col"
  >
    <template #title>
      <div class="flex items-center space-x-2">
        <ElInput
          v-model="keyword"
          size="large"
          :placeholder="$t('scenes.searchScene')"
          clearable
        >
          <template #append>
            <ElButton :icon="ElSearch" />
          </template>
        </ElInput>
        <ElButton
          v-if="isAdmini"
          @click="uploadFile"
          title="$t('page.resources.uploadFile')"
          class="p-2"
        >
          <ElIcon><ElUploadFilled /></ElIcon>
        </ElButton>
      </div>
    </template>
    <div class="flex h-full w-full">
      <div class="sticky top-0 hidden w-1/3 p-4 lg:block">
        <!-- 分类导航 -->
        <div class="flex w-full flex-wrap justify-start gap-2 overflow-x-auto">
          <span
            v-for="category in categories"
            :key="category.name"
            @click="selectCategory(category.name)"
            class="flex cursor-pointer items-center gap-1 rounded-full px-4 py-2 text-sm font-medium transition-all"
            :class="
              selectedCategory === category.name
                ? 'bg-black text-white'
                : 'bg-gray-100 text-gray-700'
            "
          >
            {{ category.name }}
          </span>
        </div>

        <!-- 资源类别及格式 -->
        <div class="mt-4 space-y-4">
          <div v-for="(formats, category) in resources" :key="category">
            <div class="flex items-center gap-2">
              <component :is="icons[category]" class="h-5 w-5 text-gray-600" />
              <span class="text-sm font-semibold">{{ category }}</span>
            </div>
            <div class="mt-2 flex w-full flex-wrap gap-2">
              <span
                v-for="format in formats"
                :key="format"
                @click="selectFileType(format, category)"
                class="cursor-pointer rounded-full px-4 py-1 text-sm transition-all"
                :class="
                  selectedFileTypes.includes(format)
                    ? 'bg-blue-500 text-white'
                    : 'bg-gray-200 text-gray-700'
                "
              >
                {{ format }}
              </span>
            </div>
          </div>
        </div>
      </div>

      <div class="w-full overflow-y-auto bg-white p-4 lg:w-2/3 dark:bg-black">
        <!-- 骨架屏 (Skeleton) -->
        <div v-if="isLoading" class="grid gap-2 md:grid-cols-1 xl:grid-cols-2">
          <ElCard v-for="n in 10" :key="n" shadow="hover" class="p-2 shadow-lg">
            <ElSkeleton animated>
              <template #template>
                <div class="flex justify-between">
                  <div class="flex w-full flex-col space-y-2">
                    <ElSkeletonItem
                      variant="text"
                      style="width: 60%; height: 16px"
                    />
                    <div class="flex items-center space-x-2">
                      <ElSkeletonItem
                        variant="image"
                        style="width: 32px; height: 32px"
                      />
                      <ElSkeletonItem
                        variant="text"
                        style="width: 20%; height: 14px"
                      />
                      <ElSkeletonItem
                        variant="text"
                        style="width: 30%; height: 14px"
                      />
                    </div>
                  </div>
                </div>

                <div class="mt-5 flex justify-between">
                  <div class="flex items-center space-x-2">
                    <ElSkeletonItem
                      variant="circle"
                      style="width: 30px; height: 30px"
                    />
                    <ElSkeletonItem
                      variant="text"
                      style="width: 150px; height: 14px"
                    />
                  </div>
                  <div class="flex space-x-2">
                    <ElSkeletonItem
                      variant="circle"
                      style="width: 30px; height: 30px"
                    />
                    <ElSkeletonItem
                      variant="circle"
                      style="width: 30px; height: 30px"
                    />
                    <ElSkeletonItem
                      variant="circle"
                      style="width: 30px; height: 30px"
                    />
                    <ElSkeletonItem
                      variant="circle"
                      style="width: 30px; height: 30px"
                    />
                  </div>
                </div>
              </template>
            </ElSkeleton>
          </ElCard>
        </div>

        <!-- 实际文件内容 -->
        <div
          v-if="!isLoading && filteredFiles.length > 0"
          class="grid gap-4 md:grid-cols-1 lg:grid-cols-1 xl:grid-cols-2"
        >
          <ElCard
            v-for="file in filteredFiles"
            :key="file.id"
            shadow="hover"
            class="cursor-pointer p-3 shadow-lg"
            :body-style="{ padding: '4px' }"
            @click="getResourceInfo(file)"
          >
            <div class="flex justify-between">
              <div class="flex flex-col space-y-2">
                <span class="text-base font-bold text-blue-500">
                  {{ file.name.replace(/\.[^.]+$/, '') }}
                </span>
                <div
                  class="flex items-center space-x-2 text-sm text-gray-500 dark:text-amber-50"
                >
                  <img :src="imageSrc(file.type)" class="h-8 w-8" />
                  <p>{{ file.type }}</p>
                  <ElDivider direction="vertical" />
                  <span class="font-xs">更新时间：</span>
                  <time class="font-xs italic">{{ file.updatedTime }}</time>
                </div>
              </div>
            </div>

            <!-- 操作按钮 -->
            <div
              class="mt-5 flex justify-between border-t pt-2 text-sm text-gray-600"
            >
              <div class="flex items-center space-x-2">
                <ElAvatar
                  v-if="adminInfo.avatar"
                  :src="adminInfo.avatar"
                  :size="25"
                  class="cursor-pointer hover:scale-110"
                />
                <ElAvatar v-else :size="30" class="cursor-pointer">
                  {{ adminInfo.userName[0] }}
                </ElAvatar>
                <span class="cursor-pointer text-blue-500">{{
                  adminInfo.userName
                }}</span>
                <span class="dark:text-amber-50">
                  <time class="font-xs text-xs italic">{{
                    file.createdTime
                  }}</time>
                </span>
              </div>
              <div class="flex space-x-2">
                <ElTooltip content="导入" placement="top">
                  <ElButton
                    circle
                    size="small"
                    type="success"
                    :icon="ElDocumentAdd"
                    @click="importResouce(file.id)"
                  />
                </ElTooltip>
                <ElTooltip content="下载" placement="top">
                  <ElButton
                    circle
                    size="small"
                    type="primary"
                    :icon="ElDownload"
                    @click="downloadFile(file.id, file.name)"
                  />
                </ElTooltip>
                <ElTooltip content="查看" placement="top">
                  <ElButton
                    circle
                    size="small"
                    type="warning"
                    :icon="ElView"
                    @click="previewData(file.id)"
                  />
                </ElTooltip>
                <ElTooltip content="删除" placement="top" v-if="isAdmini">
                  <ElButton
                    circle
                    size="small"
                    type="danger"
                    :icon="ElDelete"
                    @click="deletePublic(file.id)"
                  />
                </ElTooltip>
                <ElTooltip content="查看标签" placement="top">
                  <ElButton
                    circle
                    size="small"
                    type="success"
                    :icon="ElPriceTag"
                    @click="addTags(file.id, file.name)"
                  />
                </ElTooltip>
                <ElTooltip content="发布" placement="top" v-if="isAdmini">
                  <ElButton
                    v-if="file.name.toLowerCase().endsWith('.geojson')"
                    circle
                    size="small"
                    :icon="ElUploadFilled"
                    @click="showPublishDialog(file.id, file.name, file.type)"
                  />
                </ElTooltip>
              </div>
            </div>
          </ElCard>
        </div>

        <!-- 无数据提示 -->
        <ElEmpty
          class="flex h-full items-center justify-center"
          v-if="!isLoading && filteredFiles.length === 0"
          description="暂无文件"
        />

        <!-- 分页 -->
        <div
          v-if="filteredFiles.length > 0"
          class="col-span-2 mt-4 flex justify-center"
        >
          <ElPagination
            v-model:current-page="currentPage"
            v-model:page-size="pageSize"
            layout="total, prev, pager, next, jumper"
            :total="total"
            background
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
          />
        </div>
      </div>
    </div>

    <!-- 上传对话框 -->
    <Uploader
      v-model="uploadFileDialog"
      v-if="uploadFileDialog"
      upload-type="public"
      @upload-success="refreshPublicResources"
    />
    <PreviewDialog
      v-if="isPreviewDialogShow"
      :preview-src="previewSrc"
      :is-preview-dialog-show="isPreviewDialogShow"
      :data-name="currentSelectedFile.name"
      :resource-info="currentSelectedFile"
      @close-preview-dialog="handleClosePreviewDialog"
    />
    <PublishDialog
      :is-publish-dialog-show="publishDialog"
      :current-selected-data="realSelectedFileData"
      :is-public="true"
      @close-publish-dialog="publishDialog = false"
      v-if="publishDialog"
    />
    <FileViewer
      v-model="dialogImport"
      v-if="isFileViewerShow"
      :is-file-viewer-show="isFileViewerShow"
      data-name="选择存储目录"
      :filter-array="filterArray"
      :catalog-id="rootCatalog as string"
      @close-file-viewer="handleCloseFileViewer"
      @confirm-select="confirmFileImport"
    />
    <!-- 打标签 -->
    <AddTagDialog
      v-model="isAddTagShow"
      v-if="isAddTagShow"
      :is-add-tag-show="isAddTagShow"
      :data-id="tagFileId"
      :data-name="tagFileName"
      :is-public="true"
      @close-add-tag-dialog="handleCloseDialog"
    />
  </Page>
</template>
